package base

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"sync"
	"time"

	"context"

	"github.com/go-redis/redis/v8"
	"gopkg.in/yaml.v2"
	"gorm.io/driver/clickhouse"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

//Config 配置
type Config struct {
	Database       Database `yaml:"database"`
	Zap            Zap      `yaml:"zap"`
	Redis          Redis    `yaml:"redis"`
	Server         Server   `yaml:"server"`
	CHDBName       string
	CHBatchCount   int `yaml:"chBatchCount"`
	cacheSchema    *sync.Map
	Mail           Mail   `yaml:"mail"`
	Rpc            Rpc    `yaml:"rpc"`
	Ui             Ui     `yaml:"ui"`
	UseOrgan       string `yaml:"useOrgan"`
	MainDataSource string `yaml:"mainDataSource"`
}

//Database 数据库的连接配置
type Database struct {
	Mysql      string `yaml:"mysql"`
	Pgsql      string `yaml:"pgsql"`
	Clickhouse string `yaml:"clickhouse"`
}

//Redis Redis连接配置
type Redis struct {
	Server   string `yaml:"server"`
	Port     string `yaml:"port"`
	Password string `yaml:"password"`
}

//Mail 邮箱连接配置
type Mail struct {
	//User 邮箱服务器连接信息
	User string `yaml:"user"`
	//Port 端口号
	Port string `yaml:"port"`
	// 如果是阿里邮箱 pass填密码，qq邮箱填授权码
	Pass string `yaml:"pass"`
	//Host 邮箱服务器
	Host string `yaml:"host"`
}

type Ui struct {
	ReportPageNum int  `yaml:"reportPageNum"`
	BrowsePageNum int  `yaml:"browsePageNum"`
	MaxExportNum  int  `yaml:"maxExportNum"`
	IsDemo        bool `yaml:"isDemo"`
}

//rpc配置
type Rpc struct {
	Tcp string `yaml:"tcp"`
}

//Zap Zap日志功能配置
type Zap struct {
	Filename   string `yaml:"filename"`
	MaxSize    int    `yaml:"maxSize"`
	MaxBackups int    `yaml:"maxBackups"`
	MaxAges    int    `yaml:"maxAges"`
	Compress   bool   `yaml:"compress"`
	Console    bool   `yaml:"console"`
}

//Server web服务器参数
type Server struct {
	//HTTPPort http端口号
	HTTPPort string `yaml:"httpPort"`
	//StaticRootPath 静态内容的根路径
	StaticRootPath string `yaml:"staticRootPath"`
	//LandingPage 首页
	LandingPage string `yaml:"landingPage"`
}

//AppConf 应用程序配置
var AppConf Config

//CHDB clickhouse数据库连接
var CHDB *gorm.DB

//MYDB mysql 数据库连接
var MYDB *gorm.DB

//RedisCli Redis访问客户端
var RedisCli *redis.Client
var rctx = context.Background()

func init() {
	var err error
	var workPath string
	if workPath, err = WorkPath(); err != nil {
		log.Panicf("获取执行路径出错%s", err.Error())
		return
	}
	filePath := workPath + "/config/app.yaml"
	if yamlBytes, err := ioutil.ReadFile(filePath); err == nil {
		if err := yaml.Unmarshal(yamlBytes, &AppConf); err != nil {
			log.Panicf("加载程序配置文件失败%s", err.Error())
			return
		}
	}
	if AppConf.Ui.MaxExportNum == 0 {
		AppConf.Ui.MaxExportNum = 100000
	}
	InitLogger()
	sidx := strings.Index(AppConf.Database.Clickhouse, "database=") + 9
	chName := AppConf.Database.Clickhouse[sidx:]
	eidx := strings.Index(chName, "&")
	chName = chName[0:eidx]
	AppConf.CHDBName = chName
	if AppConf.UseOrgan == "" {
		idx := strings.LastIndex(chName, "_")
		AppConf.UseOrgan = chName[idx+1:]
	}
	var chdb, mydb *sql.DB
	CHDB, err = gorm.Open(clickhouse.Open(AppConf.Database.Clickhouse), &gorm.Config{})
	if err != nil {
		Logger.Panic(err.Error())
	}
	chdb, err = CHDB.DB()
	if err != nil {
		Logger.Panic(err.Error())
	}
	chdb.SetConnMaxLifetime(time.Minute * 3)
	chdb.SetMaxIdleConns(10)
	chdb.SetMaxOpenConns(200)
	if AppConf.Database.Mysql != "" {
		MYDB, err = gorm.Open(mysql.Open(AppConf.Database.Mysql), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)})
		if err != nil {
			Logger.Panic(err.Error())
		}
		mydb, err = MYDB.DB()
		if err != nil {
			Logger.Panic(err.Error())
		}
		mydb.SetConnMaxLifetime(time.Minute * 3)
		mydb.SetMaxIdleConns(10)
		mydb.SetMaxOpenConns(200)
	} else if AppConf.Database.Pgsql != "" {
		MYDB, err = gorm.Open(postgres.Open(AppConf.Database.Pgsql), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)})
		if err != nil {
			Logger.Panic(err.Error())
		}
		mydb, err = MYDB.DB()
		if err != nil {
			Logger.Panic(err.Error())
		}
		mydb.SetConnMaxLifetime(time.Minute * 3)
		mydb.SetMaxIdleConns(10)
		mydb.SetMaxOpenConns(200)
	} else {
		log.Panic("AppConf.Database中的Mysql或者Pgsql必须设置一个")
		return
	}
	RedisCli = redis.NewClient(&redis.Options{
		Addr:     AppConf.Redis.Server + ":" + AppConf.Redis.Port,
		Password: AppConf.Redis.Password, // no password set
		DB:       0,                      // use default DB
	})
	err = RedisCli.Ping(rctx).Err()
	if err != nil {
		Logger.Panic(fmt.Sprintf("连接redis失败%s", err.Error()))
	}
	initWF()
	if AppConf.cacheSchema == nil {
		AppConf.cacheSchema = &sync.Map{}
	}
	err = cacheOrganAndUser()
	if err != nil {
		Logger.Panic(fmt.Sprintf("缓存部门员工失败%s", err.Error()))
	}
	filePath = workPath + "/config/bigTable.yaml"
	if yamlBytes, err := ioutil.ReadFile(filePath); err == nil {
		if err := yaml.Unmarshal(yamlBytes, &bigTabCols); err != nil {
			log.Panicf("加载大宽表配置文件失败%s", err.Error())
			return
		}
	}
}

func cacheOrganAndUser() (err error) {
	err = GetDepartmentCache().Build()
	if err != nil {
		return
	}
	err = GetEmployeeCache().Build()
	return
}
